<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="OYUHB" id="OYUHB"><span data-lake-id="u4b8e54f7" id="u4b8e54f7">典型回答</span></h1>
  <p data-lake-id="uf95e16a4" id="uf95e16a4"><br></p>
  <p data-lake-id="u80e1119d" id="u80e1119d"><span data-lake-id="u6dd827f1" id="u6dd827f1">InheritableThreadLocal是用于主子线程之间参数传递的，但是，这种方式有一个问题，那就是必须要是在主线程中手动创建的子线程才可以，而现在池化技术非常普遍了，很多时候线程都是通过线程池进行创建和复用的，这时候InheritableThreadLocal就不行了。</span></p>
  <p data-lake-id="u9aa183ac" id="u9aa183ac"><span data-lake-id="u09d69649" id="u09d69649">​</span><br></p>
  <p data-lake-id="u87ce5f1d" id="u87ce5f1d"><span data-lake-id="u451d2417" id="u451d2417">TransmittableThreadLocal是阿里开源的一个方案 （开源地址：</span><a href="https://github.com/alibaba/transmittable-thread-local" target="_blank" data-lake-id="u5d8c7ee5" id="u5d8c7ee5"><span data-lake-id="u1c8a8236" id="u1c8a8236">https://github.com/alibaba/transmittable-thread-local</span></a><span data-lake-id="u87e481f2" id="u87e481f2"> ） ，这个类继承并加强InheritableThreadLocal类。用来实现线程之间的参数传递，一经常被用在以下场景中：</span></p>
  <p data-lake-id="u9be1b05a" id="u9be1b05a"><span data-lake-id="u5cfcfa7b" id="u5cfcfa7b" class="lake-fontsize-12" style="color: rgb(31, 35, 40)">​</span><br></p>
  <ol list="u243e6db6">
   <li fid="u3a2f9e93" data-lake-id="ubc8120d1" id="ubc8120d1"><span data-lake-id="u93782d16" id="u93782d16" class="lake-fontsize-12" style="color: rgb(31, 35, 40)">分布式跟踪系统 或 全链路压测（即链路打标）</span></li>
   <li fid="u3a2f9e93" data-lake-id="u3cb172ae" id="u3cb172ae"><span data-lake-id="u8290035a" id="u8290035a" class="lake-fontsize-12" style="color: rgb(31, 35, 40)">日志收集记录系统上下文</span></li>
   <li fid="u3a2f9e93" data-lake-id="ua1cbd3c3" id="ua1cbd3c3"><span data-lake-id="u34e11499" id="u34e11499" class="lake-fontsize-11" style="color: rgb(31, 35, 40)">Session</span><span data-lake-id="u8df68212" id="u8df68212" class="lake-fontsize-12" style="color: rgb(31, 35, 40)">级</span><span data-lake-id="ucfbf0f2e" id="ucfbf0f2e" class="lake-fontsize-11" style="color: rgb(31, 35, 40)">Cache</span></li>
   <li fid="u3a2f9e93" data-lake-id="u7cccb31d" id="u7cccb31d"><span data-lake-id="u4fd3070c" id="u4fd3070c" class="lake-fontsize-12" style="color: rgb(31, 35, 40)">应用容器或上层框架跨应用代码给下层</span><span data-lake-id="ufacdf700" id="ufacdf700" class="lake-fontsize-11" style="color: rgb(31, 35, 40)">SDK</span><span data-lake-id="ubb6fa459" id="ubb6fa459" class="lake-fontsize-12" style="color: rgb(31, 35, 40)">传递信息</span></li>
  </ol>
  <p data-lake-id="u07d14a25" id="u07d14a25"><span data-lake-id="u3272f9df" id="u3272f9df" class="lake-fontsize-12" style="color: rgb(31, 35, 40)">​</span><br></p>
  <h1 data-lake-id="RZfbr" id="RZfbr"><span data-lake-id="ud50a24bf" id="ud50a24bf" style="color: rgb(31, 35, 40)">扩展知识</span></h1>
  <h2 data-lake-id="fjdyC" id="fjdyC"><span data-lake-id="uc5a24aa5" id="uc5a24aa5">使用方式</span></h2>
  <p data-lake-id="u08b43fb9" id="u08b43fb9"><br></p>
  <p data-lake-id="u6ac7f07a" id="u6ac7f07a"><span data-lake-id="ufef60951" id="ufef60951" class="lake-fontsize-12">先需要导入依赖：</span></p>
  <p data-lake-id="u33886d92" id="u33886d92"><span data-lake-id="u8971330a" id="u8971330a" class="lake-fontsize-12">​</span><br></p>
  <pre lang="java"><code>
&lt;dependency&gt;
    &lt;groupId&gt;com.alibaba&lt;/groupId&gt;
    &lt;artifactId&gt;transmittable-thread-local&lt;/artifactId&gt;
    &lt;version&gt;2.14.2&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
  <p data-lake-id="uaa5b72d8" id="uaa5b72d8"><br></p>
  <p data-lake-id="uc0b9c448" id="uc0b9c448"><span data-lake-id="ufd4e8124" id="ufd4e8124" class="lake-fontsize-12">对于简单的父子线程之间参数传递，可以用以下方式：</span></p>
  <p data-lake-id="u189c44fb" id="u189c44fb"><span data-lake-id="ucb78973b" id="ucb78973b" class="lake-fontsize-12">​</span><br></p>
  <pre lang="java"><code>
TransmittableThreadLocal&lt;String&gt; context = new TransmittableThreadLocal&lt;&gt;();

// 在父线程中设置
context.set("value-set-in-parent");

// 在子线程中可以读取，值是"value-set-in-parent"
String value = context.get();
</code></pre>
  <p data-lake-id="u1d59a166" id="u1d59a166"><br></p>
  <p data-lake-id="u233d0bad" id="u233d0bad"><span data-lake-id="u31afdcb4" id="u31afdcb4" class="lake-fontsize-12">如果在线程池中，可以用如下方式使用：</span></p>
  <p data-lake-id="u31d559ea" id="u31d559ea"><span data-lake-id="u47ed21a4" id="u47ed21a4" class="lake-fontsize-12">​</span><br></p>
  <pre lang="java"><code>
TransmittableThreadLocal&lt;String&gt; context = new TransmittableThreadLocal&lt;&gt;();

// 在父线程中设置
context.set("value-set-in-parent");

Runnable task = new RunnableTask();
// 额外的处理，生成修饰了的对象ttlRunnable
Runnable ttlRunnable = TtlRunnable.get(task);
executorService.submit(ttlRunnable);


// Task中可以读取，值是"value-set-in-parent"
String value = context.get();
</code></pre>
  <p data-lake-id="u1c9adc7f" id="u1c9adc7f"><br></p>
  <p data-lake-id="uff0dda43" id="uff0dda43"><span data-lake-id="ue8e3a09b" id="ue8e3a09b" class="lake-fontsize-12">除了Runnable，Callable也支持：</span></p>
  <p data-lake-id="u181d1fa1" id="u181d1fa1"><span data-lake-id="u2863c54a" id="u2863c54a" class="lake-fontsize-12">​</span><br></p>
  <pre lang="java"><code>
TransmittableThreadLocal&lt;String&gt; context = new TransmittableThreadLocal&lt;&gt;();


// 在父线程中设置
context.set("value-set-in-parent");

Callable call = new CallableTask();
// 额外的处理，生成修饰了的对象ttlCallable
Callable ttlCallable = TtlCallable.get(call);
executorService.submit(ttlCallable);


// Call中可以读取，值是"value-set-in-parent"
</code></pre>
  <p data-lake-id="uc3fc04b9" id="uc3fc04b9"><br></p>
  <p data-lake-id="uf9d9ef0e" id="uf9d9ef0e"><span data-lake-id="u7b35219a" id="u7b35219a" class="lake-fontsize-12">也可以直接用在线程池上，而不是Runnable和Callable上：</span></p>
  <p data-lake-id="u840949ac" id="u840949ac"><span data-lake-id="u3e121cfb" id="u3e121cfb" class="lake-fontsize-12">​</span><br></p>
  <pre lang="java"><code>
ExecutorService executorService = ...
// 额外的处理，生成修饰了的对象executorService
executorService = TtlExecutors.getTtlExecutorService(executorService);

TransmittableThreadLocal&lt;String&gt; context = new TransmittableThreadLocal&lt;&gt;();


// 在父线程中设置
context.set("value-set-in-parent");

Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);


// Task或是Call中可以读取，值是"value-set-in-parent"
String value = context.get();
</code></pre>
 </body>
</html>